<html>
<head>
    <title>touchPad</title>
    <meta content="" name="Description">
    <meta content="" name="Keywords">
    <meta charset="UTF-8">
    <!--坑爹的IE兼容-->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!--坑爹的将360默认为极速模式打开-->
    <meta name="renderer" content="webkit">
    <!--移动优先-->
    <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">

    <!--//不缓存-->
    <META HTTP-EQUIV="pragma" CONTENT="no-cache">
    <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
    <META HTTP-EQUIV="expires" CONTENT="0">
    <style>
        /* reset */
        html,body,h1,h2,h3,h4,h5,h6,div,dl,dt,dd,ul,ol,li,p,blockquote,pre,hr,figure,table,caption,th,td,form,fieldset,legend,input,button,textarea,menu{margin:0;padding:0;}
        header,footer,section,article,aside,nav,hgroup,address,figure,figcaption,menu,details{display:block;}
        table{border-collapse:collapse;border-spacing:0;}
        caption,th{text-align:left;font-weight:normal;}
        html,body,fieldset,img,iframe,abbr{border:0;}
        i,cite,em,var,address,dfn{font-style:normal;}
        [hidefocus],summary{outline:0;}
        li{list-style:none;}
        h1,h2,h3,h4,h5,h6,small{font-size:100%;}
        sup,sub{font-size:83%;}
        pre,code,kbd,samp{font-family:inherit;}
        q:before,q:after{content:none;}
        textarea{overflow:auto;resize:none;}
        label,summary{cursor:default;}
        a,button{cursor:pointer;}
        h1,h2,h3,h4,h5,h6,em,strong,b{font-weight:bold;}
        del,ins,u,s,a,a:hover{text-decoration:none;}
        body,textarea,input,button,select,keygen,legend{font:12px/1.14 arial,\5b8b\4f53;color:#333;outline:0;}
        body{background:#fff;}
        a,a:hover{color:#333;}

        .keys{
            position: fixed;
            height: 100%;
            width: 100%;
        }
        .keys>div{
            height: 100%;
            width: 2.925%;
            float: left;
            border:1px solid rgba(196, 196, 196, 0.28);
            text-align: center;
            font-size: 1.4rem;
            font-weight: bold;
            line-height: 0.7;
        }
        .keys>div:active {
            border:1px solid rgba(196, 48, 29, 0.28);
        }
        .black{
            background: #dbdbdb;
        }
    </style>
</head>
<body onload="init()">
<div class="keys" style="height: 100%">
    <!--<div data-keyindex="0" class="key"><br>1<br>·</div>-->
    <!--<div data-keyindex="1" class="key black"></div>-->
    <!--<div data-keyindex="2" class="key"><br>2<br>·</div>-->
    <!--<div data-keyindex="3" class="black key"></div>-->
    <!--<div data-keyindex="4" class="key"><br>3<br>·</div>-->
    <div data-keyindex="5" class="key"><br>4<br>·</div>
    <div data-keyindex="6" class="black key"></div>
    <div data-keyindex="7" class="key"><br>5<br>·</div>
    <div data-keyindex="8" class="black key"></div>
    <div data-keyindex="9" class="key"><br>6<br>·</div>
    <div data-keyindex="10" class="black key"></div>
    <div data-keyindex="11" class="key"><br>7<br>·</div>
    <div data-keyindex="12" class="key"><br>1</div>
    <div data-keyindex="13" class="black key"></div>
    <div data-keyindex="14" class="key"><br>2</div>
    <div data-keyindex="15" class="black key"></div>
    <div data-keyindex="16" class="key"><br>3</div>
    <div data-keyindex="17" class="key"><br>4</div>
    <div data-keyindex="18" class="black key"></div>
    <div data-keyindex="19" class="key"><br>5</div>
    <div data-keyindex="20" class="black key"></div>
    <div data-keyindex="21" class="key"><br>6</div>
    <div data-keyindex="22" class="black key"></div>
    <div data-keyindex="23" class="key"><br>7</div>
    <div data-keyindex="24" class="key">·<br>1</div>
    <div data-keyindex="25" class="black key"></div>
    <div data-keyindex="26" class="key">·<br>2</div>
    <div data-keyindex="27" class="black key"></div>
    <div data-keyindex="28" class="key">·<br>3</div>
    <div data-keyindex="29" class="key">·<br>4</div>
    <div data-keyindex="30" class="black key"></div>
    <div data-keyindex="31" class="key">·<br>5</div>
    <div data-keyindex="32" class="black key"></div>
    <div data-keyindex="33" class="key">·<br>6</div>
    <div data-keyindex="34" class="black key"></div>
    <div data-keyindex="35" class="key">·<br>7</div>
</div>
<div id="log" style="position: fixed;bottom: 5px;left: 5px">
    调试信息
</div>
<script>
    var context;
    var hz=[
//        130.81,
//        138.59,
//        146.83,
//        155.56,
//        164.81,
        174.61, 185, 196, 207.65, 220, 233.08, 246.94, 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392, 415.3, 440, 466.16, 493.88, 523.25, 554.37, 587.33, 622.25, 659.25, 698.46, 739.99, 783.99, 830.61, 880, 932.33, 987.77,]
    var sounds={}
    var DynamicsCompressorNode
    function init(){
        try {
            window.AudioContext = window.AudioContext||window.webkitAudioContext;
            context = new AudioContext();

            DynamicsCompressorNode=context.createDynamicsCompressor()
            //todo 在这里设置压缩效果器的参数，包括：
            /*
            * DynamicsCompressorNode.threshold 只读
             比例系数 AudioParam 型。分贝高于此值时，将会进行压缩。
             DynamicsCompressorNode.knee 只读
             比例系数 AudioParam 型。当超出 threshold 设置的值之后，曲线在哪个点开始朝着 ratio 设置的部分平滑变换。
             DynamicsCompressorNode.ratio 只读
             比例系数 AudioParam 型。输入增益变化多少来产生 1 dB 的输出。
             DynamicsCompressorNode.reduction 只读
             float 型。表示当前压缩器使用的增益压缩值。
             DynamicsCompressorNode.attack 只读
             比例系数 AudioParam 型。降低增益 10 dB 的时间（单位为秒）。
             DynamicsCompressorNode.release 只读
             比例系数 AudioParam 型。提升增益 10 dB 的时间（单位为秒）。

                etc。
             compressor.threshold.setValueAtTime(-50, audioCtx.currentTime);
             compressor.knee.setValueAtTime(40, audioCtx.currentTime);
             compressor.ratio.setValueAtTime(12, audioCtx.currentTime);
             compressor.attack.setValueAtTime(0, audioCtx.currentTime);
             compressor.release.setValueAtTime(0.25, audioCtx.currentTime);
            *
            * */

            DynamicsCompressorNode.connect(context.destination)

        }
        catch(e){
            return alert('MLGB 你的浏览器连个Web-Audio-API 都不支持！！')

        }
        //给body绑定触摸事件，监听触摸开始，移动，结束，进行播放，变调，收音的操作
        var body=document.body
        body.addEventListener('touchstart',soundUpdate,false)
        body.addEventListener('touchend',soundOver,false)
        body.addEventListener('touchmove',soundUpdate,false)

    }

    //声音构造函数
    function Sound(hz,gain,startX,startY){
        //创建波形
        this.oscillator=context.createOscillator()
        this.oscillator.type='sine'
        this.oscillator.frequency.value=hz

        //设置音量增益
        this.gainNode=context.createGain()
        this.gainNode.gain.value=gain

        //波形——》音量——》压缩器——》输出
        this.oscillator.connect(this.gainNode)
        this.gainNode.connect(DynamicsCompressorNode)
        this.oscillator.start()
        this.startX=startX
        this.startY=startY
        return this
    }
    //通过压强计算音量的函数
    function getGain(radiusX,radiusY){
        //设定参考接触面
        var gain=radiusX*radiusY/2500
        log('音量变化：'+radiusX+'+'+radiusY+'='+gain)
        return radiusX*radiusY/2500

    }

    //触摸开始时触发，更新所有声音的同时，添加新的声音
    function soundUpdate(evt){
//        evt.preventDefault();//阻止浏览器继续处理触摸事件
        console.log(evt)

        var changedTouches=evt.touches
        var loglist=[]
        for( var key in changedTouches){
            if(key==='length'||key==='item'){
                continue
            }
            var touch=changedTouches[key]
            if(sounds[key]==undefined){
                var keyindex=touch.target.dataset.keyindex
                // 如果sound里面没有，那么创建，
                sounds[key]=new Sound(hz[keyindex],getGain(touch.radiusX,touch.radiusY),touch.pageX,touch.pageY)
            }else{
                //否则调整声音
                var sound=sounds[key]
                //todo 计算频率偏移量
                //todo 计算音色变化
                //设定音量
                sound.gainNode.gain.value=getGain(touch.radiusX,touch.radiusY)
            }
//            loglist.push([touch.radiusX,touch.radiusY,getGain(touch.radiusX,touch.radiusY)])
        }
//        log(JSON.stringify(loglist))

    }
    //触摸结束后，进行余音处理，最后删除该声音
    function soundOver(evt){
        console.log('结束音开始')
        console.log(evt)
        var changedTouches=evt.changedTouches
        for( var key in changedTouches) {
            if (key === 'length' || key === 'item') {
                continue
            }

            //todo 根据结束之前的接触面积计算尾音时长（太JB难实现了，考虑接共振箱吧）
            var sound=sounds[key]
            sound.oscillator.stop()
            sound.oscillator.disconnect(sound.gainNode)
            sound.gainNode.disconnect(DynamicsCompressorNode)
            sounds[key]=undefined
        }
    }

    function log(text){
        //连接：oscillator → destination
        document.querySelector('#log').innerText=text

    }


</script>
</body>
</html>